#ifdef __cplusplus
extern "C"{
#endif

#include "xs_def.h"
#include "xs_stack.h"
#include "xs_malloc.h"
#include "xs_log.h"

/******************************************************************************/
xs_stack_t* xs_stack_new(size_t max)
{
    xs_stack_t* _this;

    _this        = (xs_stack_t*)xs_calloc(1, sizeof(xs_stack_t));
    _this->max   = (max == 0) ? INT_MAX : max;
    _this->size  = SD_STACK_INIT_SIZE;
    _this->sp    = 0;
    _this->array = (void **)xs_calloc(_this->size, sizeof(*_this->array));

    return _this;
}

/******************************************************************************/
void xs_stack_delete(xs_stack_t* _this, void (*free_data_fn)(void *))
{
    if (!_this)
	return;

    xs_stack_clear(_this, free_data_fn);

    xs_free(_this->array);
    XS_FREE_FUNCTION(_this);
}

/******************************************************************************/
size_t xs_stack_get_nelem(const xs_stack_t* _this)
{
    return _this ? _this->sp : (size_t)-1;
}

/******************************************************************************/
void xs_stack_clear(xs_stack_t* _this, void (*free_data_fn)(void *))
{
    if (!_this)
	return;

    if (free_data_fn) {
    while (_this->sp > 0) {
        free_data_fn(_this->array[--(_this->sp)]);
	}
    }
}

/******************************************************************************/
void* xs_stack_begin(xs_stack_t* _this)
{
    if (!_this)
		return NULL;

    _this->iter = 0;
    return _this->array[_this->iter];
}

/******************************************************************************/
void* xs_stack_next(xs_stack_t* _this)
{
    if (_this && _this->iter < _this->sp)
        return _this->array[_this->iter++];

	return NULL;
}

/******************************************************************************/
void* xs_stack_end(xs_stack_t* _this)
{
    return xs_stack_peek(_this);
}

/******************************************************************************/
void* xs_stack_peek(xs_stack_t* _this)
{
    if (!_this || !_this->sp)
		return NULL;

    return _this->array[_this->sp - 1];
}

/******************************************************************************/
int xs_stack_push(xs_stack_t* _this, void *data)
{
    if (_this == NULL)
    return -1;

    if (_this->sp == _this->size) {
		size_t new_size;

        if (_this->size == _this->max)
			return -1;

        if (_this->size * 2 > _this->max) {
            new_size = _this->max;
		} else {
            new_size = _this->size * 2;
		}
        _this->size = new_size;
        _this->array = (void **)xs_realloc(_this->array, sizeof(*_this->array) * _this->size);
	}

    assert(_this->sp <= _this->size);

    _this->array[_this->sp++] = data;
	return 0;
}

/******************************************************************************/
void* xs_stack_pop(xs_stack_t* _this)
{
    if (_this == NULL || _this->sp == 0)
	return NULL;

    if (_this->size >= SD_STACK_INIT_SIZE * 4 && _this->sp < _this->size / 4)
	{
        size_t new_size = _this->size / 2;

        _this->size = new_size;
        _this->array = (void **)xs_realloc(_this->array, sizeof(*_this->array) * _this->size);
	}
    if((int)_this->sp < 0 && _this->sp <= _this->size)
	{
        printf("_this->sp < 0 or   _this->sp <= _this->size");
	}
    assert(_this->sp > 0 && _this->sp <= _this->size);
    return _this->array[--(_this->sp)];
}

int xs_stack_test(void)
{
    char *ptr[10] = { "hello","how", "are", "you", "?"};
    int i = 0;
    char * pop;
    xs_stack_t *new_stack = NULL;
    new_stack = xs_stack_new(0);
   // printf("max = %d  sp = %d  size = %d itlr = %d\n", (int)new_stack ->max, (int)new_stack ->sp, (int)new_stack ->size, (int)new_stack ->iter);

    for(i = 0; i < 5; i++)
    {
        xs_logd("%s", ptr[i]);
        xs_stack_push(new_stack, ptr[i]);
    }
#if 1
    for(i = 0; i < 5; i++){
        pop = xs_stack_pop(new_stack);
        xs_logd("i = %d  sp = %d  size = %d, %s", i, (int)new_stack->sp, (int)new_stack ->size, pop);
    }
#else
    pop = xs_stack_pop(new_stack);
    printf("----%s\n", pop);
    pop = xs_stack_pop(new_stack);
    printf("----%s\n", pop);
    pop = xs_stack_pop(new_stack);
    printf("----%s\n", pop);
    pop = xs_stack_pop(new_stack);
    printf("----%s\n", pop);
    pop = xs_stack_pop(new_stack);
    printf("----%s\n", pop);
#endif

    xs_stack_delete(new_stack, XS_FREE_FUNCTION);

    return 0;
}


#ifdef __cplusplus
}
#endif
